<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <meta name="google-site-verification" content="yF8HXsFuCTrePDFRnSkN2kkzV2ypBjtywzXsfVXOOV8">
  <meta name="baidu-site-verification" content="VxrVAiQAZ9">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"yang0033.gitee.io","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":true,"preload":true},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="一、关于 lint对于已经搭建CI开发环境的团队来说，代码规范管理必然会成为团队协作的基石。但人工的CodeReview中加入格式及规范检查会存在如下问题  技术含量低，大量重复劳动 容易出现误判 规范变更同步困难，难以维护  针对以上问题，代码lint概念诞生。 历史背景相比其他技术，代码lint其实由来已久。维基百科解释，lint 作为一种工具程序，主要负责静态源码分析，负责代码规范、代码缺陷">
<meta property="og:type" content="article">
<meta property="og:title" content="iOS  lint 自动化试水">
<meta property="og:url" content="http://yang0033.gitee.io/2019/08/18/iOS%20%20lint%20%E8%87%AA%E5%8A%A8%E5%8C%96%E8%AF%95%E6%B0%B4/index.html">
<meta property="og:site_name" content="SuperYang&#96;s Blog">
<meta property="og:description" content="一、关于 lint对于已经搭建CI开发环境的团队来说，代码规范管理必然会成为团队协作的基石。但人工的CodeReview中加入格式及规范检查会存在如下问题  技术含量低，大量重复劳动 容易出现误判 规范变更同步困难，难以维护  针对以上问题，代码lint概念诞生。 历史背景相比其他技术，代码lint其实由来已久。维基百科解释，lint 作为一种工具程序，主要负责静态源码分析，负责代码规范、代码缺陷">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/1445110-14876261b2abdef7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/1445110-6480889f624cdbea?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/1445110-3c5b44a7b188b319?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/1445110-a3048f84a7369a79?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/1445110-d4613607f4186ecd?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/1445110-de69fadb90cf144d?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/1445110-304de04615cac023?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/1445110-f085aad7d429cdf5?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="article:published_time" content="2019-08-18T11:53:00.000Z">
<meta property="article:modified_time" content="2020-07-09T08:00:43.245Z">
<meta property="article:author" content="SuperYang">
<meta property="article:tag" content="工程管理">
<meta property="article:tag" content="DevOps">
<meta property="article:tag" content="lint">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://upload-images.jianshu.io/upload_images/1445110-14876261b2abdef7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">

<link rel="canonical" href="http://yang0033.gitee.io/2019/08/18/iOS%20%20lint%20%E8%87%AA%E5%8A%A8%E5%8C%96%E8%AF%95%E6%B0%B4/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>iOS  lint 自动化试水 | SuperYang`s Blog</title>
  
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-71812998-3"></script>
    <script>
      if (CONFIG.hostname === location.hostname) {
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', 'UA-71812998-3');
      }
    </script>


  <script>
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?8ff3295288514de6f89f314c23ee40ab";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">SuperYang`s Blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">落魄程序员在线炒饭</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
        <li class="menu-item menu-item-message">

    <a href="/message/" rel="section"><i class="fa fa-music fa-fw"></i>留言板 | Music</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://yang0033.gitee.io/2019/08/18/iOS%20%20lint%20%E8%87%AA%E5%8A%A8%E5%8C%96%E8%AF%95%E6%B0%B4/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="https://tva2.sinaimg.cn/crop.259.17.290.290.180/c2abdfa9jw8ez7appr3p2j20g40a2t91.jpg?KID=imgbed,tva&Expires=1594186820&ssig=BdxhDdi1Ti">
      <meta itemprop="name" content="SuperYang">
      <meta itemprop="description" content="牛肉炒饭不要香菜，老板收钱">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="SuperYang`s Blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          iOS  lint 自动化试水
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-08-18 19:53:00" itemprop="dateCreated datePublished" datetime="2019-08-18T19:53:00+08:00">2019-08-18</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2020-07-09 16:00:43" itemprop="dateModified" datetime="2020-07-09T16:00:43+08:00">2020-07-09</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/iOS/" itemprop="url" rel="index"><span itemprop="name">iOS</span></a>
                </span>
            </span>

          
            <span id="/2019/08/18/iOS%20%20lint%20%E8%87%AA%E5%8A%A8%E5%8C%96%E8%AF%95%E6%B0%B4/" class="post-meta-item leancloud_visitors" data-flag-title="iOS  lint 自动化试水" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2019/08/18/iOS%20%20lint%20%E8%87%AA%E5%8A%A8%E5%8C%96%E8%AF%95%E6%B0%B4/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2019/08/18/iOS%20%20lint%20%E8%87%AA%E5%8A%A8%E5%8C%96%E8%AF%95%E6%B0%B4/" itemprop="commentCount"></span>
    </a>
  </span>
  
  <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>6k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>5 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="一、关于-lint"><a href="#一、关于-lint" class="headerlink" title="一、关于 lint"></a>一、关于 lint</h1><p>对于已经搭建CI开发环境的团队来说，代码规范管理必然会成为团队协作的基石。但人工的CodeReview中加入格式及规范检查会存在如下问题</p>
<ol>
<li>技术含量低，大量重复劳动</li>
<li>容易出现误判</li>
<li>规范变更同步困难，难以维护</li>
</ol>
<p>针对以上问题，代码<code>lint</code>概念诞生。</p>
<h2 id="历史背景"><a href="#历史背景" class="headerlink" title="历史背景"></a>历史背景</h2><p>相比其他技术，代码lint其实由来已久。<a href="https://en.wikipedia.org/wiki/Lint_(software)" target="_blank" rel="noopener">维基百科</a>解释，lint 作为一种工具程序，主要负责静态源码分析，负责代码规范、代码缺陷等检测，最早出现在 Unix 系统中，用于C语言代码检测。</p>
<h2 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h2><p>而在实际lint 场景中，凡是作为第三方检测校验的辅助工具都可算lint范畴。比如：<br>|                 | 主要用途                     |<br>|—————–|————————–|<br>| commitizen lint | 检测 git commit 提交信息规范 |<br>| eslint          | 静态检测 js 代码规范及缺陷   |<br>| imageSizeLint   | 检查项目中的异常尺寸图片检测 |</p>
<a id="more"></a> 
<h2 id="常用的代码-lint-库"><a href="#常用的代码-lint-库" class="headerlink" title="常用的代码 lint 库"></a>常用的代码 lint 库</h2><table>
<thead>
<tr>
<th>语言</th>
<th>lint 库</th>
</tr>
</thead>
<tbody><tr>
<td>Objective-C</td>
<td>OCLint</td>
</tr>
<tr>
<td>Swift</td>
<td>SwiftLint</td>
</tr>
<tr>
<td>java(android)</td>
<td>AndroidStudio Lint</td>
</tr>
<tr>
<td>kotlin</td>
<td>klint</td>
</tr>
<tr>
<td>javascript</td>
<td>eslint</td>
</tr>
<tr>
<td>go</td>
<td>golint</td>
</tr>
</tbody></table>
<h2 id="lint-可参与的生命周期"><a href="#lint-可参与的生命周期" class="headerlink" title="lint 可参与的生命周期"></a>lint 可参与的生命周期</h2><p><img src="https://upload-images.jianshu.io/upload_images/1445110-14876261b2abdef7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image"></p>
<h3 id="IDE-支持"><a href="#IDE-支持" class="headerlink" title="IDE 支持"></a>IDE 支持</h3><p>Jetbrain 出品的系列 IDE（WebStorm、AndroidStudio、AppCode）、VSCode 都拥有丰富的 lint 插件，大多数是基于常用lint库开发的。上述的两个 IDE 除了Objective-C，其他语言基本都支持。<br>Xcode 已不再支持插件植入，但可以通过 Xcode 辅助API，在编译时进行 lint 错误日志输出，代表作为 OClint、SwiftLint。</p>
<h3 id="其他周期"><a href="#其他周期" class="headerlink" title="其他周期"></a>其他周期</h3><p>除了 IDE 支持，其他的生命周期均可使用 lint 库自带的命令行工具实现。</p>
<h1 id="二、定制自己的-lint-工作流"><a href="#二、定制自己的-lint-工作流" class="headerlink" title="二、定制自己的 lint 工作流"></a>二、定制自己的 lint 工作流</h1><p>看完上面的介绍，大家可能会想。我只要在 CI 阶段集成 lint 不就一劳永逸了？这里其实会类比一个场景— SVN 和 Git 的特性差异，其中最主要的一个就是<code>集中式</code>和<code>分布式</code>。<br>说回 lint 流，当一些 lint 检查，堆积在一个 PR 提交时再做最终拦截时，会有以下问题：</p>
<ol>
<li>反馈链太长，要到最后 PR 跑 CI 才能监听到。</li>
<li>CI单点反馈影响因素较多，包括网速、CI机器性能、代码集成等等。</li>
<li>修复体验差，无法针对已修复的问题做实时验证。<br>综上，我们需要根据<code>分布式</code>和<code>集中式</code>的问题进行相互补充。<blockquote>
<p>关于 <code>集中式</code> lint 模式也有非常<a href="https://www.sonarqube.org/" target="_blank" rel="noopener">完善的实践</a>，但侧重点和本文讨论主题有所差异，这里不做深入讨论。</p>
</blockquote>
</li>
</ol>
<p><img src="https://upload-images.jianshu.io/upload_images/1445110-6480889f624cdbea?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="多 repo 场景"><br>根据上图，我们尝试解决如下问题：</p>
<ol>
<li>在代码的不同阶段，均有 lint 进行监控。</li>
<li>每个阶段均有 lint 配置中心进行规则分发。</li>
<li>多个 repo 项目，同时由 lint 配置中心进行统一管理，特指后端微服务、前端多 repo 这种场景。</li>
<li>最终的信息收集会通过 CI 检测后，通过反馈服务进行邮件同步，反馈每次CI集成的质量，lint质量作为集成质量的一个子集。</li>
</ol>
<h1 id="如何实现-iOS-的-lint-流管理"><a href="#如何实现-iOS-的-lint-流管理" class="headerlink" title="如何实现 iOS 的 lint 流管理"></a>如何实现 iOS 的 lint 流管理</h1><p>根据上文的环节，我们需要逐步进行实现。</p>
<h2 id="IDE编辑器实践"><a href="#IDE编辑器实践" class="headerlink" title="IDE编辑器实践"></a>IDE编辑器实践</h2><p>对于 iOS，你有如下选择</p>
<table>
<thead>
<tr>
<th>IDE Type</th>
<th>OCLint</th>
<th>SwiftLint</th>
<th>IDE default lint</th>
</tr>
</thead>
<tbody><tr>
<td>Xcode</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td>AppCode</td>
<td>❌</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td>VSCode</td>
<td>nonsupport</td>
<td>✅</td>
<td>❌</td>
</tr>
</tbody></table>
<p>如上，除了 VSCode 不支持 OC 之外，其他编辑器大大小小都集成了lint环境。</p>
<p>其中，只有 AppCode 支持代码编辑实时反馈。</p>
<p>IDE default lint 基本不支持自定义规则制定，大家在使用时可以有所取舍。</p>
<h3 id="Xcode-lint-集成"><a href="#Xcode-lint-集成" class="headerlink" title="Xcode lint 集成"></a>Xcode lint 集成</h3><p>Xcode 支持的lint检查，基本都是要基于编译的，所以 lint 结果查看位置比较特别，并不是在代码书写时实时反馈的，如下图所示。<br><img src="https://upload-images.jianshu.io/upload_images/1445110-3c5b44a7b188b319?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image"><br><img src="https://upload-images.jianshu.io/upload_images/1445110-a3048f84a7369a79?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image"></p>
<h4 id="OCLint-集成"><a href="#OCLint-集成" class="headerlink" title="OCLint 集成"></a>OCLint 集成</h4><p>OCLint 官网提供了<a href="http://docs.oclint.org/en/stable/guide/xcode.html" target="_blank" rel="noopener">《Use OCLint in Xcode》</a>进行 Xcode 集成。并且为项目级别 lint，需要跟随编译进行lint检测。</p>
<h4 id="SwitLint-集成"><a href="#SwitLint-集成" class="headerlink" title="SwitLint 集成"></a>SwitLint 集成</h4><p>官网提供的<a href="https://github.com/realm/SwiftLint/blob/40ddc9f25429648e2328f4fae8a666e0a569e581/README.md#xcode" target="_blank" rel="noopener">《Use Swift in Xcode》</a>，配置更简单，同样为项目级 lint，跟随编译进行。<strong>这里强烈推荐使用 Pod 集成，主要可以降低大家集成的成本（避开Homebrew，路径配置这些成本）,其他好处下文 git lint 关节会提到。</strong><br>但可以通过命令行方式进行<a href="https://github.com/realm/SwiftLint/blob/40ddc9f25429648e2328f4fae8a666e0a569e581/README.md#command-line" target="_blank" rel="noopener">单个文件 Lint</a>，使用方式如下。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ swiftlint lint &lt;source file0&gt; &lt;source file1&gt; ...</span><br></pre></td></tr></table></figure>



<h4 id="default-lint"><a href="#default-lint" class="headerlink" title="default lint"></a>default lint</h4><p>主要指 <code>Clang Static Analyzer</code>，是 Xcode 编译时自己产生的 warning 及 error，但缺乏代码风格检查，不过多赘述。</p>
<h3 id="AppCode-lint-配置"><a href="#AppCode-lint-配置" class="headerlink" title="AppCode lint 配置"></a>AppCode lint 配置</h3><h4 id="SwiftLint"><a href="#SwiftLint" class="headerlink" title="SwiftLint"></a>SwiftLint</h4><p>使用 JetBrain 插件进行集成，具体可以参考<a href="https://plugins.jetbrains.com/plugin/9175-swiftlint" target="_blank" rel="noopener">这里</a>。</p>
<h4 id="IDE-Default-lint"><a href="#IDE-Default-lint" class="headerlink" title="IDE Default lint"></a>IDE Default lint</h4><p><img src="https://upload-images.jianshu.io/upload_images/1445110-d4613607f4186ecd?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image"><br><img src="https://upload-images.jianshu.io/upload_images/1445110-de69fadb90cf144d?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image"><br>除了编辑是的实时反馈，手动 lint 和 JetBrain 其他编辑器一样，通过自带的 Inspect Code 功能实现，并且可以指定 lint 的范围和需要检测的规则，如上图。</p>
<h3 id="VSCode"><a href="#VSCode" class="headerlink" title="VSCode"></a>VSCode</h3><p>VSCode 仅支持 SwiftLint 的应用市场插件，使用非常小众，不做赘述。</p>
<h3 id="IDE-lint-总结"><a href="#IDE-lint-总结" class="headerlink" title="IDE lint 总结"></a>IDE lint 总结</h3><p>综上，考虑到统一性和扩展性，优先推荐 AppCode 进行日常代码的开发和 lint 反馈，更加轻量，不依赖编译。</p>
<h2 id="编译-lint"><a href="#编译-lint" class="headerlink" title="编译 lint"></a>编译 lint</h2><p>在上文 IDE Lint 其实已经涉及到编译 lint，不管是 OCLint 还是 SwiftLint 天然支持，这里也不再过多赘述。</p>
<h2 id="Git-提交-lint"><a href="#Git-提交-lint" class="headerlink" title="Git 提交 lint"></a>Git 提交 lint</h2><p>本次试水耗时最长的环节，描述一下在这个时机做 lint 的优势。</p>
<ol>
<li>只 lint 最小范围，即本次提交的 staged 区的文件，文件最少，性能最优。</li>
<li>老项目存在的通病，由于老旧代码没有适配新的 lint 规则，导致在项目 lint 适配之前，基本无法通过 <code>IDE lint</code>和<code>编译 lint</code>。</li>
<li>除了和上面的周期同样具备分布式性能优势，相对反馈周期相比CI也更及时，粒度为每个 commit。</li>
</ol>
<p>所以，对于公司自己的项目，由于老旧代码 lint 规则适配周期较长，我们首先在项目中集成了这个时机的 lint。</p>
<h3 id="Git-Lint-Flow"><a href="#Git-Lint-Flow" class="headerlink" title="Git Lint Flow"></a>Git Lint Flow</h3><p><img src="https://upload-images.jianshu.io/upload_images/1445110-304de04615cac023?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image"></p>
<p>由于 OCLint 配置相对繁杂，我们先拿 SwiftLint 练手。如上图，我们需要按照流程实现这2个关键点。</p>
<ol>
<li>lint 环境配置。</li>
<li>commit hook 触发器。</li>
</ol>
<h4 id="lint-环境配置"><a href="#lint-环境配置" class="headerlink" title="lint 环境配置"></a>lint 环境配置</h4><p>在上文的 <code>IDE Lint</code> 环节其实已经介绍了，SwiftLint 支持单文件的 lint。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ swiftlint lint &lt;source file0&gt; &lt;source file1&gt; ...</span><br></pre></td></tr></table></figure>
<p>但如何将其与 git hook 完美结合？</p>
<p>不出意外你会遇到以下问题：</p>
<ol>
<li>git hook 的维护困难，需要自己编写完 hook 脚本后，在群里告诉大家把脚本复制到 <code>.git</code> 目录中。</li>
<li>git hook 默认使用 shell 编写，需要一定的 shell 经验。</li>
<li>如何判断出哪些是待提交的文件，虽然 Git 提供了相关的命令，但需要自己和 git hook 做事件绑定。</li>
<li>判断出待提交文件后，如何在 lint 失败时跳出 commit 并提供有好的提示？</li>
</ol>
<p>这个在 iOS 领域基本没有相关的实践，不如我们抬头看下其他技术栈的解决方案。</p>
<p><img src="https://upload-images.jianshu.io/upload_images/1445110-f085aad7d429cdf5?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image"><br>上图是前端关于 <code>eslint</code> 的一个解决方案。</p>
<p>说一下这几个环节</p>
<p><strong>husky</strong>：主要负责对 git hook 的管理，实际上是一个 node 编写的触发器，并且对 git hook 做了依赖反转，方便你的 repo 或者其他配置中心统一管理，避免 .git 目录频繁的复制粘贴。附<a href="https://github.com/typicode/husky" target="_blank" rel="noopener">《husky 使用教程》</a>。</p>
<p><strong>lint-staged</strong>：主要负责检测 Git 待提交的文件，并将 list 提交给 lint 工具。附<a href="https://github.com/okonet/lint-staged" target="_blank" rel="noopener">《lint-staged 使用教程》</a></p>
<p><strong>lint 工具</strong>：<code>eslint</code>、<code>SwiftLint</code> 等 lint 工具。</p>
<h4 id="动手实践"><a href="#动手实践" class="headerlink" title="动手实践"></a><strong>动手实践</strong></h4><ol>
<li><p>在项目根目录配置 package.json</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"name"</span>: <span class="string">"ycMath"</span>,</span><br><span class="line">  <span class="attr">"version"</span>: <span class="string">"0.0.1"</span>,</span><br><span class="line">  <span class="attr">"private"</span>: <span class="literal">true</span>,</span><br><span class="line">  "devDependencies": &#123; # 在开发环境配置两个工具</span><br><span class="line">    "husky": "^2.7.0",</span><br><span class="line">    "lint-staged": "^8.2.1"</span><br><span class="line">  &#125;,</span><br><span class="line">  "husky": &#123;</span><br><span class="line">    "hooks": &#123;</span><br><span class="line">      "pre-commit": "lint-staged" # 指定在 pre-commit hook 时触发 lint-staged</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  "lint-staged": &#123;</span><br><span class="line">    "linters": &#123;</span><br><span class="line">      "*.swift":["Pods/SwiftLint/swiftlint lint"] # 使用pod安装 SwiftLint</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li><p>根目录执行 npm install(这里默认大家都安装了 npm，因为实在太高频使用了😂)</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install</span><br></pre></td></tr></table></figure>
<p><strong>note!: 这里不要忘记在 .gitignore 文件里忽略根目录的 <code>node_modules</code> 这个文件夹。</strong></p>
</li>
<li><p>创建一个新的 swift 文件进行验证</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ vim AppDelegate.swift # 在文件里写一写超长注释，比如218个字符的注释。</span><br></pre></td></tr></table></figure></li>
<li><p>得到反馈结果，并提交失败</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">$ git add .</span><br><span class="line">$ git commit -m &quot;test&quot;</span><br><span class="line">husky &gt; pre-commit (node v8.9.1)</span><br><span class="line">  ↓ Stashing changes... [skipped]</span><br><span class="line">    → No partially staged files found...</span><br><span class="line">  ❯ Running linters...</span><br><span class="line">    ❯ Running tasks for *.swift</span><br><span class="line">      ✖ Pods&#x2F;SwiftLint&#x2F;swiftlint lint</span><br><span class="line"></span><br><span class="line">✖ Pods&#x2F;SwiftLint&#x2F;swiftlint lint found some errors. Please fix them and try committing again.</span><br><span class="line">&#x2F;Users&#x2F;chaoyang&#x2F;Dev&#x2F;testLint&#x2F;AppDelegate.swift</span><br><span class="line">⛔️ Line 27: Line should be 120 characters or less: currently 218 characters</span><br><span class="line">⚠️ Line 40: Line should be 120 characters or less: currently 128 characters</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<p>至此，你的 git lint 环节已经完成功能。</p>
</li>
</ol>
<h4 id="基于-DRY-继续优化"><a href="#基于-DRY-继续优化" class="headerlink" title="基于 DRY 继续优化"></a>基于 <code>DRY</code> 继续优化</h4><p>在把这些教程和原理同步大家后，发现很多人会忘记 <code>npm install</code> lint 工具，或者不知道如何安装。本着 <code>DRY</code> 原则，能不重复的工作尽量不要重复。<br>那么我需要解决以下问题：</p>
<ol>
<li>如何探测大家的 lint 环境是否安装完毕？</li>
<li>如果有探测方案，应该选在什么时机？</li>
<li>如果探测到，如何提示开发者进行安装？</li>
</ol>
<p>针对问题，又开始了新一轮的探索，终于在<a href="https://blog.dianqk.org/2017/05/01/dev-on-pod/" target="_blank" rel="noopener">《基于 cocoapod 进行 iOS 开发》</a>这片文章找到了灵感。</p>
<ol>
<li>配置你的 Podfile，在里面添加如下 ruby 代码<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">## lint 插件校验</span><br><span class="line">pre_install do |installer|</span><br><span class="line">  # 获取插件路径</span><br><span class="line">  sandbox_root &#x3D; Pathname(installer.sandbox.root)</span><br><span class="line">  ycroot &#x3D; File.expand_path(&quot;..&quot;, sandbox_root)</span><br><span class="line">  node_module_lint_stage &#x3D; File.expand_path(&quot;node_modules&#x2F;lint-staged&#x2F;&quot;,ycroot)</span><br><span class="line">  node_module_husky &#x3D; File.expand_path(&quot;node_modules&#x2F;husky&quot;,ycroot)</span><br><span class="line">  </span><br><span class="line">  has_lint_stage &#x3D; File.exist?(node_module_lint_stage)</span><br><span class="line">  has_husky &#x3D; File.exist?(node_module_husky)</span><br><span class="line">  </span><br><span class="line">  # 检查是否安装 lint-staged 及 husky</span><br><span class="line">  if has_husky &amp;&amp; has_lint_stage</span><br><span class="line">    Pod::UI.puts &quot;lint staged 和 husky 存在，请继续。&quot;</span><br><span class="line">  else</span><br><span class="line">    # 方案一</span><br><span class="line">    raise &quot;warning by @SuperYang\n\nYCLog error： lint staged 或 husky 不存在， 请使用以下命令安装: npm install &quot;</span><br><span class="line"></span><br><span class="line">    # 这里的异常提示可能不太友好，如果你觉得大家本地都是必装 npm 的，你可以使用下面的方案二</span><br><span class="line">    # 方案二</span><br><span class="line">    # Pod::UI.puts &quot;lint staged 和 husky 不存在，正在尝试安装。&quot;</span><br><span class="line">    # &#96;rm -rf node_modules &amp;&amp; npm install&amp;&amp;echo lint staged 和 husky 安装完毕&#96;</span><br><span class="line">    # Pod::UI.puts &quot;lint staged 和 husky 完成安装🍺🍺🍺~~~&quot;</span><br><span class="line">  end</span><br><span class="line">end</span><br></pre></td></tr></table></figure></li>
<li>在根目录删除 <code>node_modules</code> 目录。<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ rm -rf node_modules</span><br></pre></td></tr></table></figure></li>
<li>执行 pod install或update 命令。<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ pod install</span><br></pre></td></tr></table></figure></li>
<li>查看错误提示</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># 方案一</span><br><span class="line">[!] An error occurred while processing the pre-install hook of the Podfile.</span><br><span class="line"></span><br><span class="line">warning by @SuperYang</span><br><span class="line"></span><br><span class="line">YCLog error： lint staged 或 husky 不存在， 请使用以下命令安装: npm install</span><br></pre></td></tr></table></figure>

<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># 方案二</span><br><span class="line">lint staged 和 husky 不存在，正在尝试安装。</span><br><span class="line">lint staged 和 husky 完成安装🍺🍺🍺~~~</span><br></pre></td></tr></table></figure>

<blockquote>
<p>强烈推荐方案二，实测额外问题很少，只有几个人的新电脑忘装<code>npm</code>。</p>
</blockquote>
<h2 id="CI-Lint-配置-amp-自动化-lint-报告"><a href="#CI-Lint-配置-amp-自动化-lint-报告" class="headerlink" title="CI Lint 配置 &amp; 自动化 lint 报告"></a>CI Lint 配置 &amp; 自动化 lint 报告</h2><p>上文花了大幅度的篇幅介绍了几个场景的 lint 玩法，关于CI lint 和 反馈报告发送环节，本文不做详细介绍，之后会在项目实战中进行测试，完成后会通过博客分享给大家。</p>
<h1 id="三、总结"><a href="#三、总结" class="headerlink" title="三、总结"></a>三、总结</h1><ul>
<li><p>回顾一下我们的知识点</p>
<ol>
<li>基于<code>分布式</code>思想的 lint 架构设计。</li>
<li>对于不同生命周期的lint实践</li>
<li>对于 git commit lint 环节的设计及实践。<br>以上环节，git lint 是使用后感觉最轻量的，也是最容易自动化完成的流程。对于老旧项目对lint规则还未及时适配的，优先推荐进行实践，从文件级别进行检测，也是业界比较常用的 lint 切口。</li>
</ol>
</li>
<li><p>以上方案的大多数设计，同样适用于其他技术栈。</p>
</li>
<li><p>当一个问题出现时，首先要接受他的必然性，同时尽量避难闭门造车，同样的问题，其他人肯定也会遇到，更不要把自己束缚在自己的技术栈。拥抱更广的社区，拥抱其他技术栈😎。</p>
</li>
<li><p>本文涉及的其他技术栈<code>nodeJS</code>、<code>Ruby</code>、<code>Git</code>等。</p>
</li>
</ul>

    </div>

    
    
    
        

  <div class="followme">
    <p>欢迎关注我的其它发布渠道</p>

    <div class="social-list">

        <div class="social-item">
          <a target="_blank" class="social-link" href="https://www.jianshu.com/u/f37a8f0ba6f8">
            <span class="icon">
              <i class="fas fa-book"></i>
            </span>

            <span class="label">简书</span>
          </a>
        </div>
    </div>
  </div>


      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E5%B7%A5%E7%A8%8B%E7%AE%A1%E7%90%86/" rel="tag"># 工程管理</a>
              <a href="/tags/DevOps/" rel="tag"># DevOps</a>
              <a href="/tags/lint/" rel="tag"># lint</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2018/11/08/iOS%20%E4%BD%BF%E7%94%A8%20agvtool%20%E7%AE%A1%E7%90%86%E9%A1%B9%E7%9B%AE%E7%89%88%E6%9C%AC%E5%8F%B7/" rel="prev" title="使用 agvtool 管理项目版本号">
      <i class="fa fa-chevron-left"></i> 使用 agvtool 管理项目版本号
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/03/16/gitflow%20%E8%A7%84%E8%8C%83%E5%8F%8A%E5%B7%A5%E5%85%B7%E6%95%B4%E7%90%86/" rel="next" title="gitflow 规范及工具整理">
      gitflow 规范及工具整理 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          
    <div class="comments" id="valine-comments"></div>

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#一、关于-lint"><span class="nav-number">1.</span> <span class="nav-text">一、关于 lint</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#历史背景"><span class="nav-number">1.1.</span> <span class="nav-text">历史背景</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#使用场景"><span class="nav-number">1.2.</span> <span class="nav-text">使用场景</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#常用的代码-lint-库"><span class="nav-number">1.3.</span> <span class="nav-text">常用的代码 lint 库</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#lint-可参与的生命周期"><span class="nav-number">1.4.</span> <span class="nav-text">lint 可参与的生命周期</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#IDE-支持"><span class="nav-number">1.4.1.</span> <span class="nav-text">IDE 支持</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#其他周期"><span class="nav-number">1.4.2.</span> <span class="nav-text">其他周期</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#二、定制自己的-lint-工作流"><span class="nav-number">2.</span> <span class="nav-text">二、定制自己的 lint 工作流</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#如何实现-iOS-的-lint-流管理"><span class="nav-number">3.</span> <span class="nav-text">如何实现 iOS 的 lint 流管理</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#IDE编辑器实践"><span class="nav-number">3.1.</span> <span class="nav-text">IDE编辑器实践</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Xcode-lint-集成"><span class="nav-number">3.1.1.</span> <span class="nav-text">Xcode lint 集成</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#OCLint-集成"><span class="nav-number">3.1.1.1.</span> <span class="nav-text">OCLint 集成</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#SwitLint-集成"><span class="nav-number">3.1.1.2.</span> <span class="nav-text">SwitLint 集成</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#default-lint"><span class="nav-number">3.1.1.3.</span> <span class="nav-text">default lint</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#AppCode-lint-配置"><span class="nav-number">3.1.2.</span> <span class="nav-text">AppCode lint 配置</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#SwiftLint"><span class="nav-number">3.1.2.1.</span> <span class="nav-text">SwiftLint</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#IDE-Default-lint"><span class="nav-number">3.1.2.2.</span> <span class="nav-text">IDE Default lint</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#VSCode"><span class="nav-number">3.1.3.</span> <span class="nav-text">VSCode</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#IDE-lint-总结"><span class="nav-number">3.1.4.</span> <span class="nav-text">IDE lint 总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#编译-lint"><span class="nav-number">3.2.</span> <span class="nav-text">编译 lint</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Git-提交-lint"><span class="nav-number">3.3.</span> <span class="nav-text">Git 提交 lint</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Git-Lint-Flow"><span class="nav-number">3.3.1.</span> <span class="nav-text">Git Lint Flow</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#lint-环境配置"><span class="nav-number">3.3.1.1.</span> <span class="nav-text">lint 环境配置</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#动手实践"><span class="nav-number">3.3.1.2.</span> <span class="nav-text">动手实践</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#基于-DRY-继续优化"><span class="nav-number">3.3.1.3.</span> <span class="nav-text">基于 DRY 继续优化</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#CI-Lint-配置-amp-自动化-lint-报告"><span class="nav-number">3.4.</span> <span class="nav-text">CI Lint 配置 &amp; 自动化 lint 报告</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#三、总结"><span class="nav-number">4.</span> <span class="nav-text">三、总结</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="SuperYang"
      src="https://tva2.sinaimg.cn/crop.259.17.290.290.180/c2abdfa9jw8ez7appr3p2j20g40a2t91.jpg?KID=imgbed,tva&Expires=1594186820&ssig=BdxhDdi1Ti">
  <p class="site-author-name" itemprop="name">SuperYang</p>
  <div class="site-description" itemprop="description">牛肉炒饭不要香菜，老板收钱</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">39</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">5</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">31</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/yangchao0033" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;yangchao0033" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:ygrfwyc@gmail.com" title="E-Mail → mailto:ygrfwyc@gmail.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://weibo.com/yangchao0033" title="Weibo → https:&#x2F;&#x2F;weibo.com&#x2F;yangchao0033" rel="noopener" target="_blank"><i class="fab fa-weibo fa-fw"></i>Weibo</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://www.jianshu.com/u/f37a8f0ba6f8" title="简书 → https:&#x2F;&#x2F;www.jianshu.com&#x2F;u&#x2F;f37a8f0ba6f8" rel="noopener" target="_blank"><i class="fas fa-book fa-fw"></i>简书</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://t.me/superYang0033" title="Telegram → https:&#x2F;&#x2F;t.me&#x2F;superYang0033" rel="noopener" target="_blank"><i class="fab fa-telegram fa-fw"></i>Telegram</a>
      </span>
  </div>



      </div>

      
        <div id="music163player">
        <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=350 height=86 src="//music.163.com/outchain/player?type=2&id=31473269&auto=0&height=66">
        </iframe>
        </div>
    </div>

    

  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">SuperYang</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
    <span title="站点总字数">157k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">2:23</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  
  <script>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>




  
<script src="/js/local-search.js"></script>













  

  

  

  <script async src="/js/cursor/fireworks.js"></script>



<script>
NexT.utils.loadComments(document.querySelector('#valine-comments'), () => {
  NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
    var GUEST = ['nick', 'mail', 'link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item => {
      return GUEST.includes(item);
    });
    new Valine({
      el         : '#valine-comments',
      verify     : true,
      notify     : true,
      appId      : 'zizRqalUJY55Xc5oBJKbhxpV-gzGzoHsz',
      appKey     : '64gPcVi8lIA8zVGpBSEk7uKu',
      placeholder: "留言板无需注册登录，快来评论吧。。",
      avatar     : 'mm',
      meta       : guest,
      pageSize   : '10' || 10,
      visitor    : true,
      lang       : '' || 'zh-cn',
      path       : location.pathname,
      recordIP   : false,
      serverURLs : ''
    });
  }, window.Valine);
});
</script>

</body>
</html>
